package com.dxtx.widget.rotatomenu;


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.TranslateAnimation;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.FrameLayout;

import com.dxtx.common.R;

import java.util.ArrayList;
import java.util.List;


/**
 * Copyright (C), 2008-2015, Huawei Tech. Co., Ltd.
 * <p/>
 * Description : 旋转式排列菜单,环形布局菜单,支持类似listView式的滑动
 *
 * @author [pWX273343] 2015年10月29日
 * @version V100R001
 * @since V100R001
 */
public class RotatoMenu extends FrameLayout {
    /**
     * 从某角度到某角度排列
     */
    // private float fromAngel = (float) Math.PI * 1.75f, toAngle = (float)
    // Math.PI * 0.75f;
    private float fromAngel = (float) Math.PI * 1.65f, toAngle = (float) Math.PI * 0.85f;
    /**
     * 角度间隔
     */
    private float angleInterval = 0;

    private BaseAdapter adapter;
    /**
     * 从角度到角度排列的默认item个数
     */
    private int numColume = 5;
    /**
     * 中央按钮
     */
    private Button centerButton = null;
    /**
     * items
     */
    private List<View> childs = new ArrayList<View>();
    /**
     * 记录item角度具体分布
     */
    private List<Float> angles = new ArrayList<Float>();
    /**
     * 开始位置
     */
    private int firstVisiablePosition = 0;
    /**
     * 环形半径
     */
    private float mRange = -1;

    /**
     * item大小
     */
    private int mItemWidth = 0, mItemHeight = 0;
    private int mMenuSize = 0;
    /**
     * 旋转中心
     */
    private int mCenterX = -1, mCenterY = -1;
    /**
     * 是否展开
     */
    private boolean isShowing = false;

    private GestureDetector detector;

    private int lastVisiablePosition = 0;

    private float startAngle = 315, sweepAngle = 180;

    private boolean isDrawRing = true;

    public RotatoMenu(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttribute(context, attrs);
        addCenterButton();
    }

    private void initAttribute(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ringMenu);

        mMenuSize = a.getDimensionPixelSize(R.styleable.ringMenu_menuSize,
                (int) context.getResources().getDimension(R.dimen._40dp));
        fromAngel = a.getInt(R.styleable.ringMenu_fromAngle, 297);
        fromAngel = (float) (fromAngel / 180 * Math.PI);
        toAngle = a.getInt(R.styleable.ringMenu_toAngle, 153);
        toAngle = (float) (toAngle / 180 * Math.PI);

        startAngle = a.getInt(R.styleable.ringMenu_ringStartAngle, 315);
        sweepAngle = a.getInt(R.styleable.ringMenu_ringSweepAngle, 180);

        mItemWidth = a.getDimensionPixelSize(R.styleable.ringMenu_itemWidth, (int) getContext().getResources()
                .getDimension(R.dimen._30dp));
        mItemHeight = a.getDimensionPixelSize(R.styleable.ringMenu_itemHeight, (int) getContext().getResources()
                .getDimension(R.dimen._30dp));

        mRange = a.getDimensionPixelSize(R.styleable.ringMenu_range, -1);
        mCenterX = a.getDimensionPixelSize(R.styleable.ringMenu_centerX, -1);
        mCenterY = a.getDimensionPixelSize(R.styleable.ringMenu_centerY, -1);

        numColume = a.getInt(R.styleable.ringMenu_numColume, 5);

        isDrawRing = a.getBoolean(R.styleable.ringMenu_drawRing, true);
        Drawable drawable = a.getDrawable(R.styleable.ringMenu_centerButtonBackgroud);
        if (drawable != null) {
            centerButton = new Button(context);
            centerButton.setBackgroundDrawable(drawable);
        }
        a.recycle();
    }

    public RotatoMenu(Context context) {
        super(context);
        addCenterButton();
    }

    /**
     * @描述:此处添加函数描述信息
     * @作者 [pWX273343] 2015年10月28日
     */
    private void initView() {
        if (mItemWidth == 0) {
            mItemWidth = (int) getContext().getResources().getDimension(R.dimen._30dp);
        }
        if (mItemHeight == 0) {
            mItemHeight = (int) getContext().getResources().getDimension(R.dimen._30dp);
        }
        if (mMenuSize == 0) {
            mMenuSize = (int) getContext().getResources().getDimension(R.dimen._40dp);
        }

        detector = new GestureDetector(getContext(), new SimpleOnGestureListener() {
            private float lastAngle = 0;
            private float firstAngle = 0;

            private boolean mAcceptEvent = false;

            @Override
            public boolean onDown(MotionEvent e) {
                return mAcceptEvent = !isInCenter(e) && !isOutSideAngle(e);
            }

            /** 是否在转盘中心,转盘中心转起来太快,不接受事件.同样跨越转盘中心的操作也会导致转盘角度快速变更 */
            private boolean isInCenter(MotionEvent e) {
                // 点击的的距离
                float distance = (float) Math.sqrt((e.getY() - mCenterY) * (e.getY() - mCenterY)
                        + (e.getX() - mCenterX) * (e.getX() - mCenterX));
                return distance < mMenuSize * 0.707;
            }

            /** 计算角度是否在item分布的角度之外,角度分布之外,角度计算会引起意外,比如突然从360度变到0,需要复杂的判断 */
            private boolean isOutSideAngle(MotionEvent e) {
                float angle = getAngleFromEventPoint(e);
                if (fromAngel >= toAngle) {
                    return angle > fromAngel || angle < toAngle;
                } else {
                    return angle < fromAngel || angle > toAngle;
                }
            }

            /** 计算角度,该方法仅仅使用于2,3,4 */
            private float getAngleFromEventPoint(MotionEvent e) {
                float y = e.getY() - mCenterY;
                float x = e.getX() - mCenterX;
                float angle = (float) Math.atan2(y, x);
                if (angle < 0) {
                    angle += Math.PI * 2;
                }
                return angle;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                if (e1 == null || e2 == null || !mAcceptEvent) {
                    return false;
                }
                if (isInCenter(e2) || isOutSideAngle(e2)) {
                    return false;
                }
                float angle0 = getAngleFromEventPoint(e1);
                if (firstAngle != angle0) {
                    lastAngle = firstAngle = angle0;
                }
                float angleTo = getAngleFromEventPoint(e2);
                // 转换成移动角度
                float angleR = (angleTo - lastAngle);
                lastAngle = angleTo;
                for (int i = 0; i < angles.size(); i++) {
                    float angle = angles.remove(i);
                    angles.add(i, angle + angleR);
                }
                // 顺时针
                if (angleR > 0) {
                    float lastAngle = angles.get(angles.size() - 1);
                    float firstAngle = angles.get(0);
                    // 最后一个view滑出,但超过边界
                    if (lastVisiablePosition == adapter.getCount() - 1 && lastAngle > toAngle) {
                        angles.clear();
                        // 最后不能滑动
                        for (int i = 0; i < childs.size(); i++) {
                            // 从末尾逐条向前添加,从toAngle开始
                            angles.add(0, toAngle - angleInterval * i);
                        }
                        applyChildsAngleToLocation();
                        return false;
                    }
                    // 已经等于边界值,直接不在响应
                    else if (lastVisiablePosition == adapter.getCount() - 1 && lastAngle == toAngle) {
                        return false;
                    }

                    // 当最后一个View的角度,大于toAngle,即可以创建新的view时候
                    if (lastAngle > toAngle + Math.PI / 6) {
                        // 查看当前位置下面是否还有View
                        if (lastVisiablePosition < adapter.getCount() - 1) {
                            View child = adapter.getView(++lastVisiablePosition, null, null);
                            childs.add(child);
                            angles.add(lastAngle + angleInterval);

                            LayoutParams p = new LayoutParams(mItemWidth, mItemHeight);
                            addView(child, getChildCount() - 1, p);
                        } else {
                            return false;
                        }
                    }
                    if (firstAngle > fromAngel - angleInterval) {
                        // gaiView已经不可见,可以移除
                        View child = childs.remove(0);
                        angles.remove(0);
                        removeView(child);
                        // selection
                        firstVisiablePosition++;
                    }
                }
                // 逆时针旋转
                else {
                    float lastAngle = angles.get(angles.size() - 1);
                    float firstAngle = angles.get(0);
                    // 第一个边界超过
                    if (firstVisiablePosition == 0 && firstAngle < fromAngel) {
                        angles.clear();
                        // 最后不能滑动
                        for (int i = 0; i < childs.size(); i++) {
                            angles.add(angleInterval * i + fromAngel);
                        }
                        applyChildsAngleToLocation();
                        return false;
                    } else if (firstVisiablePosition == 0 && firstAngle == fromAngel) {
                        return false;
                    }

                    if (firstAngle < fromAngel) {
                        // 查看当前位置上面是否还有View
                        if (firstVisiablePosition > 0) {
                            View child = adapter.getView(firstVisiablePosition - 1, null, null);
                            childs.add(0, child);
                            angles.add(0, firstAngle - angleInterval);
                            LayoutParams p = new LayoutParams(mItemWidth, mItemHeight);
                            addView(child, getChildCount() - 1, p);
                            firstVisiablePosition--;
                        } else {
                            // 不可继续滚动
                            return false;
                        }
                    }
                    if (lastAngle < toAngle + angleInterval) {
                        // 最后一个View已经不可见,移除
                        View child = childs.remove(childs.size() - 1);
                        angles.remove(angles.size() - 1);
                        removeView(child);
                        lastVisiablePosition--;
                    }

                }
                applyChildsAngleToLocation();
                return true;
            }
        });

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        paint.setColor(0xffff00ff);
        paint.setStyle(Paint.Style.STROKE);
    }

    private void addCenterButton() {
        if (centerButton == null) {
            centerButton = new Button(getContext());
            centerButton.setBackgroundResource(android.R.drawable.btn_radio);
        }
        FrameLayout.LayoutParams p = new LayoutParams(mMenuSize, mMenuSize);
        addView(centerButton, p);

        centerButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // 弹出或收起菜单
                if (isShowing) {
                    collapse();
                } else {
                    expand();
                }
            }

        });
    }

    public BaseAdapter getAdapter() {
        return adapter;
    }

    public void setAdapter(BaseAdapter adapter) {
        this.adapter = adapter;
        initView();
        // 清除原来的view
        if (childs != null || !childs.isEmpty()) {
            for (int i = 0; i < childs.size(); i++) {
                View view = childs.get(i);
                removeView(view);
                childs.remove(view);
            }
            angles.clear();
        }
        // 上层View个数,中央button为一个
        if (numColume <= adapter.getCount()) {
            // 计算平均分布的角度
            angleInterval = (toAngle - fromAngel) / (numColume - 1);
            // 从起始位置,取numcolume个视图
            for (int i = firstVisiablePosition; i < adapter.getCount() && i < firstVisiablePosition + numColume; i++) {

                View child = adapter.getView(i, null, null);
                child.setVisibility(isShowing ? View.VISIBLE : View.INVISIBLE);
                childs.add(child);
                LayoutParams p = new LayoutParams(mItemWidth, mItemHeight);
                addView(child, getChildCount() - 1, p);

                // 排列的角度

                float angle = angleInterval * i + fromAngel;
                angles.add(angle);
                lastVisiablePosition = i;

            }
        } else {
            angleInterval = (toAngle - fromAngel) / adapter.getCount();
            for (int i = 0; i < adapter.getCount(); i++) {

                View child = adapter.getView(i, null, null);
                child.setVisibility(isShowing ? View.VISIBLE : View.INVISIBLE);
                childs.add(child);
                LayoutParams p = new LayoutParams(mItemWidth, mItemHeight);
                addView(child, getChildCount() - 1, p);
                // 排列的角度
                float angle = angleInterval + fromAngel;
                angles.add(angle);
            }
            lastVisiablePosition = adapter.getCount() - 1;
        }
        // refreshChilds();
    }

    private boolean firstMeasure = true;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        if (firstMeasure) {
            firstMeasure = false;
            if (mRange < 0) {
                mRange = width / 2 - mItemWidth / 2 - getPaddingLeft();
            }
            if (mCenterX < 0 || mCenterY < 0) {
                mCenterX = width / 2;
                mCenterY = width / 2;
            }
            applyChildsAngleToLocation();
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (centerButton != null)
            // 布局中按钮的位置
            centerButton.layout(mCenterX - mMenuSize / 2, mCenterY - mMenuSize / 2, mCenterX + mMenuSize / 2, mCenterY
                    + mMenuSize / 2);
    }

    public int getNumColume() {
        return numColume;
    }

    /**
     * @param numColume
     * @描述:分布的个数
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setNumColume(int numColume) {
        this.numColume = numColume;
    }

    public Button getCenterButton() {
        return centerButton;
    }

    /**
     * @param centerButton
     * @param menuSize     按钮的宽高
     * @描述:设置用来弹出菜单的按钮
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setCenterButton(Button centerButton, int menuSize) {
        if (this.centerButton != null) {
            removeView(this.centerButton);
        }
        this.centerButton = centerButton;
        this.mMenuSize = menuSize;
        addCenterButton();
    }

    /**
     * @描述:收起菜单
     * @作者 [pWX273343] 2015年10月28日
     */
    public void collapse() {
        isShowing = false;
        for (int i = 0; i < childs.size(); i++) {
            View view = childs.get(i);
            view.setVisibility(View.INVISIBLE);
            TranslateAnimation translate = new TranslateAnimation(0, mCenterX - mItemWidth / 2f - view.getX(), 0,
                    mCenterY - mItemHeight / 2f - view.getY());
            translate.setDuration(250 + i * 50);
            translate.setStartOffset(i * 50);

            view.startAnimation(translate);
        }
    }

    /**
     * @描述:展开菜单
     * @作者 [pWX273343] 2015年10月28日
     */
    public void expand() {
        isShowing = true;
        for (int i = 0; i < childs.size(); i++) {
            final View view = childs.get(i);
            view.setVisibility(View.VISIBLE);
            // 移动动画
            TranslateAnimation translate = new TranslateAnimation(mCenterX - mItemWidth / 2f - view.getX(), 0, mCenterY
                    - mItemHeight / 2f - view.getY(), 0);

            translate.setDuration(250 + i * 50);
            translate.setStartOffset(i * 50);

            view.clearAnimation();
            view.startAnimation(translate);

        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent e) {
        if (isShowing) {

            detector.onTouchEvent(e);
        }
        super.dispatchTouchEvent(e);
        return true;
    }

    /**
     * @param fromAngel
     * @param toAngle
     * @描述:设置item分布的角度,如从270到180,角度以x轴方向顺时针旋转,来计算,那么从270到180就是从上往左分配
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setRotatoAngle(float fromAngel, float toAngle) {
        this.fromAngel = (float) (fromAngel / 180 * Math.PI);
        this.toAngle = (float) (toAngle / 180 * Math.PI);
    }

    public float getRange() {
        return mRange;
    }

    /**
     * @param range
     * @描述:设置旋转半径
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setRange(float range) {
        this.mRange = range;
    }

    /**
     * @return
     * @描述:菜单项大小
     * @作者 [pWX273343] 2015年10月29日
     */
    public int[] getItemSize() {
        return new int[]{mItemWidth, mItemHeight};
    }

    /**
     * @param itemWidth
     * @param itemHeight
     * @描述:设置各个菜单的大小,即宽高
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setItemSize(int itemWidth, int itemHeight) {
        this.mItemWidth = itemWidth;
        this.mItemHeight = itemHeight;
    }

    /**
     * @param centerX
     * @param centerY
     * @描述:设置旋转的中心轴
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setRotatoCenter(int centerX, int centerY) {
        this.mCenterX = centerX;
        this.mCenterY = centerY;
    }

    public int getCenterY() {
        return mCenterY;
    }

    /**
     * @param draw
     * @描述:是否需要绘制用来遮挡的圆环
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setDrawRing(boolean draw) {
        isDrawRing = draw;
    }

    /**
     * @param startAngle 从某个角度开始,如45
     * @param sweepAngle 绘制环形跨越的角度,如180
     * @param color
     * @描述:设置绘制遮盖圆环
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setDrawRingAngle(float startAngle, float sweepAngle, int color) {
        this.startAngle = startAngle;
        this.sweepAngle = sweepAngle;
        isDrawRing = true;
    }

    /**
     * @param selection
     * @描述:设置从第几个item开始
     * @作者 [pWX273343] 2015年10月29日
     */
    public void setSelection(int selection) {
        firstVisiablePosition = selection;
    }

    /**
     * @描述:讲角度分布转换成位置,并调整child位置
     * @作者 [pWX273343] 2015年10月30日
     */
    private void applyChildsAngleToLocation() {
        for (int i = 0; i < childs.size(); i++) {
            View child = childs.get(i);
            float angle = angles.get(i);
            // 计算item中心位置
            float centerX = mCenterX + (float) Math.cos(angle) * mRange;
            float centerY = mCenterY + (float) Math.sin(angle) * mRange;

            // 设置item位置
            child.setX(centerX - mItemWidth / 2);
            child.setY(centerY - mItemHeight / 2);
        }
    }

    // 擦除画笔
    private Paint paint;

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (isDrawRing) {
            canvas.drawColor(0x00ffffff);
            int saveCount = canvas.saveLayer(new RectF(canvas.getClipBounds()), null, Canvas.ALL_SAVE_FLAG);
            super.dispatchDraw(canvas);

            RectF rect = new RectF(mItemWidth / 2, mItemWidth / 2, canvas.getWidth() - mItemWidth / 2,
                    canvas.getHeight() - mItemWidth / 2);
            if (rect != null) {
                paint.setStrokeWidth(mRange - mItemWidth / 2);
                canvas.drawArc(rect, startAngle, sweepAngle, false, paint);
            }
            canvas.restoreToCount(saveCount);
        } else {
            super.dispatchDraw(canvas);
        }
    }
}


